#include "stdafx.h"
#include "XmlLite.h"

#include <stack>
#include <list>

CString CXmlLite::XmlToJson(LPCTSTR Xml)
{
	class CNode
	{
	public:
		CNode(int Level, int Parent, int Index, int  Length, LPCTSTR Name, LPCTSTR Text) :
			m_Level(Level),
			m_Parent(Parent),
			m_Index(Index),
			m_Length(Length),
			m_Name(Name),
			m_Text(Text)
		{
		}
	public:
		int m_Level;
		int m_Parent;
		int m_Index;
		int m_Length;
		CString m_Name;
		CString m_Text;
	};
	std::list<CNode> nodes;

	class CTag
	{
	public:
		CTag(int Index, LPCTSTR Bgn, LPCTSTR End) : m_Index(Index), m_Length(0), m_Bgn(Bgn), m_End(End)
		{
		}
	public:
		int m_Index;
		int m_Length;
		LPCTSTR m_Bgn;
		LPCTSTR m_End;
	};
	std::stack<CTag> tags;

	int level = 0;
	int index = 0;
	
	tags.push(CTag(0, NULL, NULL));

	for (LPCTSTR b = Xml; *b != 0;)
	{
		b = _tcschr(b, _T('<'));
		if (!b)
		{
			break;
		}

		LPCTSTR p = _tcschr(b, _T('>'));
		if (!p)
		{
			break;
		}

		if (_T('?') == b[1]) // "<%"
		{
			//
		}
		else if (_T('/') == *(p - 1)) // "/>"
		{
			nodes.push_back(CNode(
				level + 1,
				tags.top().m_Index,
				++index,
				0,
				CString(b + 1, p - b - 2), NULL));
		}
		else if (_T('/') == b[1]) // "</"
		{
			CTag& tag = tags.top();
			tags.pop();

			if (tag.m_Length > 0)
			{
				nodes.push_back(CNode(
					level,
					tags.top().m_Index,
					tag.m_Index,
					tag.m_Length,
					CString(b + 2, p - b - 2), NULL));
			}
			else
			{
				nodes.push_back(CNode(
					level,
					tags.top().m_Index,
					tag.m_Index,
					tag.m_Length,
					CString(b + 2, p - b - 2),
					CString(tag.m_End, b - tag.m_End)));
			}
			
			--level;
		}
		else // "<"
		{
			++level;

			tags.top().m_Length += 1;
			tags.push(CTag(++index, b, p + 1));
		}

		b = ++p;
	}

	class CSort
	{
	public:
		bool operator () (const CNode a, const CNode b)
		{
			return a.m_Index < b.m_Index;
		}
	};
	nodes.sort(CSort());

	CString result;
	result.Append(_T("["));

	std::list<CNode>::iterator itr = nodes.begin();
	for (; itr != nodes.end(); ++itr)
	{
		//PRINT(_T("%s[%03d] [%03d] [%03d] [%03d] [%s] [%s]"),
		//	CString(_T(' '), (itr->m_Level - 1) * 2),
		//	itr->m_Level,
		//	itr->m_Parent,
		//	itr->m_Index,
		//	itr->m_Length,
		//	itr->m_Name,
		//	itr->m_Text);

		result.Append(_T("{"));
		result.AppendFormat(_T("\"%s\": %d, "), _T("level"), itr->m_Level);
		result.AppendFormat(_T("\"%s\": %d, "), _T("parent"), itr->m_Parent);
		result.AppendFormat(_T("\"%s\": %d, "), _T("index"), itr->m_Index);
		result.AppendFormat(_T("\"%s\": %d, "), _T("length"), itr->m_Length);
		result.AppendFormat(_T("\"%s\": \"%s\", "), _T("name"), itr->m_Name);
		result.AppendFormat(_T("\"%s\": \"%s\""), _T("text"), itr->m_Text);
		result.Append(_T("}"));
		result.Append(_T(", "));
	}

	result.TrimRight(_T(", "));
	result.Append(_T("]"));

	return result;
}
